import { AmcaxRender, EntityManager, THREE } from '@amcax/web-render';
import { ManagerId } from 'nextcae-base';
import { CSCircle, CSCurve, CSCurveAttrs, CSLine, CSLineAttrs } from '../basic';
import { useRenderStore } from '../store';

// line 类型
export enum LineType {
  LINE = 'line', // 直线
  A_LINE = 'a_line', // 辅助线
  DIM_LINE = 'dim_line', // 标注线
  CIRCLE = 'circle', // 圆
  CURVE = 'curve', // 曲线
  ARC = 'arc', // 圆弧
  ELLIPSE = 'ellipse', // 椭圆
  RECTANGLE = 'rectangle', // 矩形
}
// line 类型
type Attrs = {
  [LineType.LINE]?: CSLine;
  [LineType.A_LINE]?: CSLine;
  [LineType.CIRCLE]?: CSCircle;
  [LineType.CURVE]?: CSCurve;
  [LineType.ARC]?: CSCircle;
  [LineType.DIM_LINE]?: CSLine[];
};
export class ExtraLine {
  private _assisMgr: EntityManager;
  private static instance: ExtraLine;
  private preViewLine: Attrs = {};
  private renderer: {
    mainRenderer: AmcaxRender;
    camera: THREE.PerspectiveCamera | THREE.OrthographicCamera;
    assisMgr: EntityManager;
  };
  constructor() {
    this.renderer = this.getMainRenderer();
  }
  private getMainRenderer(managerId: ManagerId = ManagerId.Assis) {
    const mainRenderer = useRenderStore.getState().mainRenderer;
    return {
      mainRenderer,
      camera: mainRenderer.cameraManager.camera,
      assisMgr: mainRenderer.getEntityManager(managerId),
    };
  }
  static getInstance(): ExtraLine {
    if (!this.instance) {
      this.instance = new ExtraLine();
    }
    return this.instance;
  }
  get assisMgr() {
    return this._assisMgr ?? this.renderer.assisMgr;
  }
  setAssisMgr(assisMgr: EntityManager) {
    this._assisMgr = assisMgr;
  }
  createUpdateLine(
    vertexs?: THREE.Vector3Tuple[],
    setting?: CSLineAttrs,
    key: LineType = LineType.LINE,
  ) {
    if (!this.preViewLine?.[key]) {
      this.preViewLine[key] = new CSLine({
        vertexes: vertexs ?? null,
        maxPoints: 1000,
        ...setting,
      });
      this.preViewLine[key].addTo(this.assisMgr.group);
    } else {
      this.preViewLine[key]?.setVertexs(vertexs);
    }
    if (setting?.color) {
      this.setColor(setting.color, key);
    }
    return this.preViewLine[key];
  }
  createUpdateDimLine(vertexs?: THREE.Vector3Tuple[][], setting?: CSLineAttrs) {
    const key = LineType.DIM_LINE;
    if (!this.preViewLine?.[key]) {
      this.preViewLine[key] = new Array<CSLine>();
      vertexs.forEach((v) => {
        const line = new CSLine({
          vertexes: v ?? null,
          maxPoints: 1000,
          color: setting?.color ?? 0x101010,
          lineWidth: setting?.lineWidth ?? 1,
          renderOrder: setting?.renderOrder ?? 0,
          ...setting,
        });
        line.addTo(this.assisMgr.group);
        this.preViewLine[key].push(line);
      });
    } else {
      vertexs.forEach((v, i) => {
        this.preViewLine[key][i]?.setVertexs(v);
      });
    }
  }

  public createUpdateCurve(
    vertexs?: THREE.Vector3Tuple[],
    setting?: CSCurveAttrs,
    key = LineType.CURVE,
  ) {
    if (!this.preViewLine[key]) {
      this.preViewLine[key] = new CSCurve({
        curvePoints: vertexs ?? null,
        maxPoints: 1000,
        ...setting,
      });
      this.preViewLine[key].addTo(this.assisMgr.group);
    } else {
      this.preViewLine[key]?.updateCurve({ curvePoints: vertexs });
    }
  }
  getLine(key: LineType) {
    return this.preViewLine?.[key];
  }
  formatedVertexs(
    vertexs: (THREE.Vector3 | THREE.Vector3Tuple)[],
  ): THREE.Vector3Tuple[] {
    return vertexs.map((v) => {
      if (v instanceof THREE.Vector3) {
        return v?.toArray();
      } else {
        return v;
      }
    });
  }
  setColor(color: number | string, key = LineType.LINE) {
    this.preViewLine[key]?.setColor(color);
  }
  clearLine(key?: LineType) {
    if (key) {
      this.preViewLine[key]?.destroy();
      this.preViewLine[key] = null;
    } else {
      for (const key in this.preViewLine) {
        if (Array.isArray(this.preViewLine[key])) {
          this.preViewLine[key]?.forEach((line) => {
            line?.destroy();
          });
          this.preViewLine[key] = null;
        } else {
          this.preViewLine[key]?.destroy();
          this.preViewLine[key] = null;
        }
      }
    }
  }
}
export const lineManager = () => {
  return ExtraLine.getInstance();
};
